package com.segment.dcore.base.component;

import com.alibaba.dubbo.common.utils.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.*;

/**
 * 记录系统日志的组件
 *
 * Created by huapeng.hhp on 2017/2/27.
 */
public class LogComponent {
	private static LogComponent logComponent = new LogComponent();

	public static LogComponent get() {
		return logComponent;
	}

	private LogComponent() {
	}

	/** LOGGER for LogComponent */
	private static final Logger LOGGER = LoggerFactory.getLogger(LogComponent.class);
	/** 日志文件日期格式 */
	private static final String FILE_DATE_FORMAT = "yyyyMMdd";
	/** log最大buffer */
	private static final int LOG_MAX_BUFFER = 1000;
	/** log定时输出频率 */
	private static final long LOG_OUTPUT_INTERVAL = 10;
	private final ConcurrentMap<String, Queue<String>> logFileSet = new ConcurrentHashMap<>();
	private final ScheduledExecutorService logScheduled = Executors.newScheduledThreadPool(2,
			new NamedThreadFactory("Service-Log", true));
	private ScheduledFuture<?> logFuture = null;

	/**
	 * 记录日志信息
	 * 
	 * @param logFileURI
	 *            log文件路径
	 * @param logmessage
	 *            log信息
	 */
	public void log(String logFileURI, String logmessage) {
		initLogFuture();
		Queue<String> logQueue = logFileSet.get(logFileURI);
		if (logQueue == null) {
			logFileSet.putIfAbsent(logFileURI, new LinkedBlockingQueue<String>());
			logQueue = logFileSet.get(logFileURI);
		}
		if (logQueue.size() < LOG_MAX_BUFFER) {
			logQueue.add(logmessage);
		} else {
			LOGGER.info(logmessage);
		}
	}

	/**
	 * 定义内部类，定义日志文件写入逻辑
	 */
	private class LogTask implements Runnable {
		public void run() {
			try {
				if (logFileSet != null && logFileSet.size() > 0) {
					for (Map.Entry<String, Queue<String>> entry : logFileSet.entrySet()) {
						try {
							Queue<String> logQueue = entry.getValue();
							// 如果没有日志需要打印，则不继续
							if (logQueue.isEmpty()) {
								continue;
							}
							String accesslog = entry.getKey();
							File file = new File(accesslog);
							File dir = file.getParentFile();
							if (null != dir && !dir.exists()) {
								dir.mkdirs();
							}
							if (LOGGER.isDebugEnabled()) {
								LOGGER.debug("Append log to " + accesslog);
							}
							if (file.exists()) {
								String now = new SimpleDateFormat(FILE_DATE_FORMAT).format(new Date());
								String last = new SimpleDateFormat(FILE_DATE_FORMAT)
										.format(new Date(file.lastModified()));
								if (!now.equals(last)) {
									File archive = new File(file.getAbsolutePath() + "." + last);
									file.renameTo(archive);
								}
							}
							FileWriter writer = new FileWriter(file, true);
							try {
								String logMessage;
								while (!logQueue.isEmpty()) {
									logMessage = logQueue.poll();
									writer.write(logMessage);
									writer.write("\r\n");
								}
								writer.flush();
							} finally {
								writer.close();
							}
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
						}
					}
				}
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			}
		}
	}

	/**
	 * 初始化logFuture
	 */
	private void initLogFuture() {
		if (logFuture == null) {
			synchronized (LogComponent.class) {
				if (logFuture == null) {
					logFuture = logScheduled.scheduleWithFixedDelay(new LogTask(), LOG_OUTPUT_INTERVAL,
							LOG_OUTPUT_INTERVAL, TimeUnit.MILLISECONDS);
				}
			}
		}
	}
}
